#include "base/Configuration.h"
#include "base/Simulator.h"
#include "base/simapi.h"
#include "base/threads/PthreadKeys.h"
#include "util/Logger.h"
#include "base/padding.h"

NEW_DELETE_OPERATORS_CPP(PthreadKeys,1);

PthreadKeys* PthreadKeys::instance=NULL;

PADDING(keydata_before);
void* PthreadKeys::key_data[MAX_NUM_CPUS][PthreadKeys::MAX_KEYS];
PADDING(keydata_after);

PthreadKeys* PthreadKeys::getInstance() {
    if (PthreadKeys::instance == NULL) {
        PthreadKeys::instance = NEW PthreadKeys();
    }
    return PthreadKeys::instance;
}

void PthreadKeys::removeInstance() {
    if (PthreadKeys::instance != NULL) {
        delete PthreadKeys::instance;
        PthreadKeys::instance = NULL;
    }
}

PthreadKeys::PthreadKeys() :
    num_cpus(global_sim->cfg.num_cpus)
{
}

PthreadKeys::~PthreadKeys () {
}

int PthreadKeys::create(pthread_key_t* key, void (*destructor)(void*)) {
    if (key_count == MAX_KEYS) {
        return 1;
    }
    int keyID = key_count++;
    for (int i=0; i<num_cpus; i++) {
        key_data[i][keyID] = NULL;
    }
    *((int*)key) = keyID;
    return 0;
}

int PthreadKeys::setspecific (pthread_key_t key, const void* value) {
    if ((int)key < 0 || (int)key >= MAX_KEYS) {
        return -1;
    }
    int const cpu = inSimulation ?
        Sim_GetMyId() : PthreadInterface::simState.cpu;
    ASSERT(cpu < num_cpus);
    key_data[cpu][key] = (void*)value;
    return 0;
}

void* PthreadKeys::getspecific (pthread_key_t key) {
    if ((int)key < 0 || (int)key >= MAX_KEYS) {
        return NULL;
    }
    int const cpu = inSimulation ?
        Sim_GetMyId() : PthreadInterface::simState.cpu;
    ASSERT(cpu < num_cpus);
    return key_data[cpu][key];
}
